package com.ksl.kinglockguard.activity;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;

import org.egret.egretframeworknative.engine.IGameEngine;
import org.egret.java.egretruntimelauncher.EgretRuntimeLauncher;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.ksl.kinglockguard.R;
import com.ksl.kinglockguard.data.Constants;
import com.ksl.kinglockguard.data.UserCountHabit;
import com.ksl.kinglockguard.domain.H5News;
import com.ksl.kinglockguard.domain.base.BaseNews;
import com.ksl.kinglockguard.game._interface.GameInterface;
import com.ksl.kinglockguard.game._interface.GameInterface.GameExitListener;
import com.ksl.kinglockguard.widget.GameLoadingView;
import com.ksl.kinglockguard.widget.common.CustomProgressDialog;
import com.lsk.open.core.MyLog;
import com.ksl.kinglockguard.game._interface.EgretGameInterface_V2;


/**
 * Egret Runtime 主入口，开发者应该参考这个 Activity 中的代码在自己的业务逻辑中实现。
 * 代码业务逻辑：
 * 1、外部调用 config 方法设置游戏id和url
 * 2、在 onCreate 里启加载 Egret Runtime。开发者也可以在主线程的任意函数来启动 Egret Runtime（比如一个按钮点击后），并非强制规定必须在 onCreate 函数中。
 * 3、在 EgretRuntimeDownloadListener.onCreateComplete 函数中启动 Egret Runtime，注意，启动 runtime的代码必须在主线程中。
 * 4、在任何时候都可以调用 gameEngine.game_engine_onStop(); 来关闭 Egret Runtime
 * 5、如果关闭 Egret Runtime但是又不关闭 Activity，请在 stop 之后切换到主线程，执行 onDestory()
 *
 * @author wander
 */
public class GamePlayActivity extends Activity implements GameExitListener{

    private static final String TAG = "GamePlayActivity";
    
    public static final String EXTRA_FROM_SHORTCUT_GAMEURL_STRING = "gameUrl";
    public static final String EXTRA_FROM_SHORTCUT_GAMENAME_STRING = "gameName";
    public static final String EXTRA_FROM_SHORTCUT_GAMEID_INT = "gameId";
    public static final String EXTRA_FROM_SHORTCUT_GAME_PLATINFOPARAM_STRING = "platInfoParam";
    
    
	//egret测试demo配置
	public static final String EGRET_APPID = "10000";
    public static final String EGRET_APPKEY = "41C223FF41467A62E4C95CD723D58974";
    public static final int EGRET_DEV = 0;
    
     
/*
	//旧版本的 appId/appKey
    public static final String EGRET_APPID = "1017";
    public static final String EGRET_APPKEY = "0eab09671d6c0560efcfa1197e1a26db";
    public static final int EGRET_DEV = 1;
*/
/*    public static final String EGRET_APPID = "18230";
    public static final String EGRET_APPKEY = "C4SsmP8BQvOwxqrvpR4Yw";
    public static final int EGRET_DEV = 0;
*/    
    // Egret所有游戏的总根目录
    private String egret_game_root;

    //用于标识单个游戏的id,此游戏的资源会存储在这个目录中
    private String egret_game_id;

    //游戏下载url，是一个 zip 文件，第一次游戏过程会下载这个 zip 文件，之后会读取本地缓存
    private String game_load_file_url;

    //Egret Runtime 的视图，内部主要包括一个 GLSurfaceView 和 一个可以定制的 Loading 界面
    private View frameLayout = null;

    //Egret Runtime 自身的加载器，负责维护 Runtime 自身的更新机制
    private EgretRuntimeLauncher launcher;
    
    private GameInterface gameInterface;

    private String from;
    private H5News mH5News;
    private Handler mHandler;
    public static final int MSG_WHAT_STOP_LOADING = 1;
    public static final int MSG_WHAT_SHOW_TIPS = 2;
    
    //Egret Runtime 的实例
    private Class<?> gameEngineClass;
    private Object gameEngine;
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyLog.d(TAG,"****** -------- onCreate-------- ******");
        setContentView(R.layout.egret_game_runner_activity);

        
		try {
			initData(getIntent());
		} catch (GameDataException e) {
			e.printStackTrace();
			Log.e(TAG,"gameplay initData exception: " + e.getMessage());
			finish();
			return;
		}

		mHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				int what = msg.what;
				switch(what) {
				case MSG_WHAT_STOP_LOADING:
					stopLoading();
					break;
				case MSG_WHAT_SHOW_TIPS:
					stopLoading();
					showTips();
					finish();
					break;
				}
			}
		};
		
        initViews();

        prepareToLoad();
    }

	private void prepareToLoad() {
		handleDirection();
		initEgretEnv();
        createRuntimeLauncher();
        startLoading();
	}

    private void handleDirection() {
    	String direction = mH5News.getPlay_game_screen_direction();
    	if(direction == null || "".equals(direction)) {
    		return ;
    	}
    	if (H5News.GAME_SCREEN_DIRECTION_HORIZON.equalsIgnoreCase(direction)) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        } else if(H5News.GAME_SCREEN_DIRECTION_VERTICAL.equalsIgnoreCase(direction)){
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        } else {
        	setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
	}

	/**
     * 1. H5列表页面		---> H5News
     * 2. 主页列表页面		---> H5News
     * 3. 快捷方式		---> gameId/gameUrl/gameName
     * 4. 锁屏界面		---> H5News
     * 5. 漂窗界面		---> PushNews
     * @param intent
     */
    private void initData(Intent intent) throws GameDataException{
    	
    	if(intent == null) {
    		throw new GameDataException("intent can NOT be null");
    	}
    	
    	from = intent.getStringExtra(Constants.FROM);

    	if(from == null || "".equals(from)) {
    		throw new GameDataException("intent extra *** from *** can NOT be null");
    	}
    	
    	
        BaseNews news = (BaseNews) intent.getSerializableExtra("curNews");
        if(from.equals(Constants.FROM_SHORT_CUT)){
        	String gameUrl = intent.getStringExtra(EXTRA_FROM_SHORTCUT_GAMEURL_STRING);
        	String gameName = intent.getStringExtra(EXTRA_FROM_SHORTCUT_GAMENAME_STRING);
        	int gameId = intent.getIntExtra(EXTRA_FROM_SHORTCUT_GAMEID_INT,-1);
        	String platInfoParam = intent.getStringExtra(EXTRA_FROM_SHORTCUT_GAME_PLATINFOPARAM_STRING);
        	//TODO 从快捷方式进来的时候，可能需要传递更多的参数
        	if(gameUrl != null && gameName !=null && gameId != -1) {
        		news = new H5News();
            	news.setArticleUrl(gameUrl);
            	news.setTitle(gameName);
            	news.setId(gameId);
            	((H5News)news).setGame_platInfoParam(platInfoParam);
        	} else {
        		throw new GameDataException("from shortcut need extra: gameName: " + gameName + 
        				" ;gameUrl: " + gameUrl + " ;gameId: " + gameId);
        	}
        }
        
        //即使news为null,也不会抛出异常
        if(news instanceof H5News) {
        	mH5News = (H5News) news;
        }

        if(mH5News == null){
        	throw new GameDataException("mH5News is null");
        }
        
        if(from.equals(Constants.FROM_SHORT_CUT)){	//统计从快捷方式进入游戏次数
        	UserCountHabit.setUserCount(GamePlayActivity.this,UserCountHabit.H5_CLICK_SHORTCUT_NUM + mH5News.getId());
        }else if(from.equals(Constants.FROM_H5_PAGE)) {	//统计从H5列表进入游戏次数
        	UserCountHabit.setUserCount(GamePlayActivity.this, UserCountHabit.EGRET_FROM_GAME + mH5News.getId());
        }
        //统计总数
    	UserCountHabit.setUserCount(GamePlayActivity.this, UserCountHabit.DESK_ACTID+mH5News.getId());
    }

    static class GameDataException extends RuntimeException {
		public GameDataException(String detailMessage) {
			super(detailMessage);
		}
    }
    
    private void initEgretEnv() {
    	if(mH5News!=null){
	        egret_game_id = String.valueOf( mH5News.getId() );
	        game_load_file_url = mH5News.getArticleUrl();
	        egret_game_root = new File(getFilesDir(), IGameEngine.EGRET_ROOT).getAbsolutePath();
    	}
    	
    	destroyRunningGame();
    }
    
    @Override
    protected void onNewIntent(Intent intent) {
    	String oldUrl = null;
    	if(mH5News != null) {
    		oldUrl = mH5News.getArticleUrl();
    	}
    	
    	try {
			initData(intent);
		} catch (GameDataException e) {
			e.printStackTrace();
			finish();
			return;
		}
    	
    	String newUrl = mH5News.getArticleUrl();
    	
    	if(newUrl == null || newUrl.endsWith(oldUrl)) {	
        	super.onNewIntent(intent);
        } else {
        	prepareToLoad();
        }
    }

    RelativeLayout egret_game_container;
    private void initViews() {
        findViewById(R.id.lay_layout).setBackgroundResource(R.drawable.bg_ss);
        egret_game_container = (RelativeLayout) findViewById(R.id.egret_game_container);
    }

// *********** loading相关 *********** start
    CustomProgressDialog mProgressDialog;
    private void startLoading() {
    	if(mProgressDialog == null) {
    		mProgressDialog = new CustomProgressDialog(this,getString(R.string.lock_loading_data));
    	}
    	if(!mProgressDialog.isShowing()) {
    		mProgressDialog.show();
    	}
        mProgressDialog.setCancelable(false);
    }
    private void stopLoading() {
        try {
			if( mProgressDialog != null && mProgressDialog.isShowing()) {
			    mProgressDialog.dismiss();
			}
		} catch (Exception e) {		//从后台日志看，确实有可能报错，因为找不到原因，只能捕获后忽略之
			//ignore
		}
    }
// *********** loading相关 *********** end
    
    private void createRuntimeLauncher() {
        launcher = new EgretRuntimeLauncher(this, egret_game_root, 
        		EGRET_APPID, EGRET_APPKEY, EGRET_DEV);

        launcher.run(new EgretRuntimeLauncher.EgretRuntimeDownloadListener() {
        	@Override
        	public void onSuccess(Class<?> gameEngineClass) {	// Egret Runtime 初始化完毕（下载成功）
        		startGame(gameEngineClass);
        	}

            @Override
            public void onError(String message) {	//当联网失败，且本地没有引擎的缓存时，走这里
                MyLog.e(TAG, "createRuntimeLauncher --- onError： "+ message);
                mHandler.sendEmptyMessage(MSG_WHAT_SHOW_TIPS);
            }

            @Override
            public void onProgress(String fileName, int currentByte, int totalByte) {
            	MyLog.d(TAG, "createRuntimeLauncher --- onProgress： " + fileName + ":" + String.valueOf(currentByte) + "/" + String.valueOf(totalByte));
            }

            @Override
			public void onProgressTotal(int currentByte, int totalByte) {
				//TODO 更新进度条
			}
        });
    }

    private void startGame(Class<?> aGameEngineClass) {
		MyLog.e(TAG, "onSuccess ------ aGameEngineClass: " + aGameEngineClass);

		gameEngineClass = aGameEngineClass;
        try {
            gameEngine = gameEngineClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        
        callSetGameOptions();
        callSetLoadingView();
        callInitRuntime();
        callSetRuntimeView();

        gameInterface = new EgretGameInterface_V2(GamePlayActivity.this, gameEngineClass, gameEngine);
	}

	private void callSetRuntimeView() {
        frameLayout = (View) callGameEngineMethod(
                GameEngineMethod.GAME_ENGINE_GET_VIEW);
        egret_game_container.addView(frameLayout);
    }
    
    private void callInitRuntime() {
        Class<?>[] initParams = { Context.class };
        Object[] initArgs = { GamePlayActivity.this };
        callGameEngineMethod(GameEngineMethod.GAME_ENGINE_INIT, initParams,
                initArgs);
    }
    private void callSetLoadingView() {
        // TODO implements your loading view
    	GameLoadingView loadingView = new GameLoadingView(this,mHandler);
        Class<?>[] loadingParams = { View.class };
        Object[] loadingArgs = { loadingView };
        callGameEngineMethod(GameEngineMethod.GAME_ENGINE_SET_LOADING_VIEW,
                loadingParams, loadingArgs);
        Class<?>[] listenerParams = { Object.class };
        callGameEngineMethod(
                GameEngineMethod.GAME_ENGINE_SET_GAME_ZIP_UPDATE_LISTENER,
                listenerParams, loadingArgs);
    }
    
    private void callSetGameOptions() {
		HashMap<String, Object> options = new HashMap<String, Object>();
        options.put("egret.runtime.libraryLoaderType", "2");
        options.put("egret.runtime.egretRoot", egret_game_root);
        options.put("egret.runtime.gameId", String.valueOf(mH5News.getId()));
        
        options.put("egret.runtime.loaderUrl", mH5News.getArticleUrl());
        //一般情况下, loaderUrl与uploadUrl是相同的。 需要进一步研究egret游戏开发的相关知识
        String egret_runtime_updateUrl = mH5News.getEgret_runtime_updateUrl();
		if(egret_runtime_updateUrl != null && !"".equals(egret_runtime_updateUrl)) {
        	options.put("egret.runtime.updateUrl", egret_runtime_updateUrl);	
        } else {
        	options.put("egret.runtime.updateUrl", mH5News.getArticleUrl());
        }

        //以下三个参数为示例游戏需要(更换游戏请注意替换)
        String game_platformType = mH5News.getGame_platformType();
		if(game_platformType != null && !"".equals(game_platformType)) {
			options.put("game_platformType", game_platformType);
        } else {
        	options.put("game_platformType", "egret");
        }
		
		String game_ServerUrl = mH5News.getGame_ServerUrl();
		if(game_ServerUrl != null && !"".equals(game_ServerUrl)) {
			options.put("game_ServerUrl", game_ServerUrl);
        } else {
        	options.put("game_ServerUrl", "http://s1.snzj.egret-labs.org/api.php");
        }
		String game_platInfoParam = mH5News.getGame_platInfoParam();
		if(game_platInfoParam != null && !"".equals(game_platInfoParam)) {
			options.put("game_platInfoParam", game_platInfoParam);
        } else {
        	options.put("game_platInfoParam", "?platInfo=open_1_9392");
        }
/*
		for(Entry e: options.entrySet()) {
        	Log.e(TAG,"key: " + e.getKey() + " ;value: " + e.getValue());
        }
*/        
        Class<?>[] params = { HashMap.class };
        Object[] args = { options };
        callGameEngineMethod(GameEngineMethod.GAME_ENGINE_SET_OPTIONS, params,
                args);
    }
    
    /**
     * 返回键交给gameInterface处理：
     * 		1. 如果游戏注册了返回键回调，则交给游戏；
     * 		2. 如果游戏未注册返回键处理，则回调activity（实现了GameExitListener接口）的onGameExit方法
     */
	@Override
	public void onBackPressed() {
		if(gameInterface != null)
			gameInterface.onBackPress();
	}
	
	@Override
	public void onGameExit() {
		//游戏退出时的逻辑处理
		MyLog.d(TAG,"onGameExit ----");
		finish();
	}

	@Override
	public void finish() {
		destroyRunningGame();
		super.finish();
	}
	
	private void destroyRunningGame() {
		finishEgretGame();
		finishGameInterface();
	}

    private void finishEgretGame() {
    	// 关闭 Egret 下载器
    	if (launcher != null) {
    		launcher.stop();
    		launcher = null;
    	}
    	
    	if (gameEngine != null) {
    		callGameEngineMethod(GameEngineMethod.GAME_ENGINE_ON_STOP);
            gameEngine = null;
        }
    	
    	frameLayout = null;
    }

    private void finishGameInterface() {
    	if(gameInterface != null) {
			gameInterface.unregisterCallBacks();
			gameInterface = null;
		}
	}

    @Override
    protected void onPause() {
        super.onPause();
        callGameEngineMethod(GameEngineMethod.GAME_ENGINE_ON_PAUSE);
    }

    @Override
    protected void onResume() {
        super.onResume();
        callGameEngineMethod(GameEngineMethod.GAME_ENGINE_ON_RESUME);
    }

    @Override
    protected void onRestart() {
        super.onRestart();
    }

    protected void onDestroy() {
        super.onDestroy();
        System.gc();
    }

    public void finalize() throws Throwable {
        super.finalize();
        MyLog.i(TAG, "EgretRuntimeActivity finalize");
    }
    
    private void showTips() {
 /*
    	StackTraceElement[] stackTrace = new Exception().getStackTrace();
    	for(StackTraceElement s: stackTrace){
    		android.util.Log.d("lijc","showTips: " + s.toString());
    	}
*/		
    	Toast.makeText(GamePlayActivity.this, R.string.failed_to_enter_game, Toast.LENGTH_SHORT).show();
    	finish();
    }
    
    private Object callGameEngineMethod(String name) {
        return callGameEngineMethod(name, null, null);
    }

    private Object callGameEngineMethod(String name, Class<?>[] params,
            Object[] args) {
        if (name == null || gameEngine == null) {
            return null;
        }

        try {
            Method method = gameEngineClass.getMethod(name, params);
            return method.invoke(gameEngine, args);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    private class GameEngineMethod {
        public static final String GAME_ENGINE_ON_RESUME =
                "game_engine_onResume";
        public static final String GAME_ENGINE_ON_PAUSE =
                "game_engine_onPause";
        public static final String GAME_ENGINE_ON_STOP =
                "game_engine_onStop";
        public static final String GAME_ENGINE_SET_OPTIONS =
                "game_engine_set_options";
        public static final String GAME_ENGINE_SET_LOADING_VIEW =
                "game_engine_set_loading_view";
        public static final String GAME_ENGINE_SET_GAME_ZIP_UPDATE_LISTENER =
                "game_engine_set_game_zip_update_listener";
        public static final String GAME_ENGINE_INIT =
                "game_engine_init";
        public static final String GAME_ENGINE_GET_VIEW =
                "game_engine_get_view";
        public static final String GAME_ENGINE_SET_ENGINE_LISTENER =
                "game_engine_set_engine_listener";
        public static final String CALL_EGRET_INTERFACE =
                "callEgretInterface";
        public static final String SET_RUNTIME_INTERFACE_SET =
                "setRuntimeInterfaceSet";
        public static final String ENABLE_EGRET_RUNTIME_INTERFACE =
                "enableEgretRuntimeInterface";
    }

    
}